package mylab.io.core.codec;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import mylab.io.base.model.Msg;
import mylab.io.core.context.CoreContext;
import mylab.io.core.event.ChannelActiveChangedEvent;
import mylab.io.core.event.ChannelIdleEvent;
import mylab.io.core.event.ChannelReadEvent;
import mylab.io.core.util.ChannelAttr;
import mylab.utils.common.guava.AsyncEventUtil;


@Slf4j
@ChannelHandler.Sharable
public abstract class AbstractInboundHandler extends SimpleChannelInboundHandler<Msg> {
    public static final String HANDLER_NAME = AbstractInboundHandler.class.getSimpleName();

    protected CoreContext<?, ?> context;

    protected AbstractInboundHandler(CoreContext<?, ?> context) {
        this.context = context;
    }

    /**
     * tcp：NioSocketChannel 对端唯一，可以获取对端地址
     * udp：NioDatagramChannel 对端不唯一，只能在收到DatagramPacket时获取对端地址
     * rxtx: RxtxChannel 对端唯一，对端地址类型 RxtxDeviceAddress  e.g. COM1, /dev/ttyUSB0, ...
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        log.info("### channelActive  ### channel id:{}", ctx.channel().id().asShortText());
        ChannelAttr.set(ctx.channel(), ChannelAttr.ATTR_DAS, context.getDas());

        AsyncEventUtil.postEvent(new ChannelActiveChangedEvent(ctx.channel(), true));
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        log.info("### channelInactive  ### channel id:{}", ctx.channel().id().asShortText());
        ChannelAttr.set(ctx.channel(), ChannelAttr.ATTR_DAS, null);

        AsyncEventUtil.postEvent(new ChannelActiveChangedEvent(ctx.channel(), false));
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Msg msg) throws Exception {
        log.debug("### channelRead0 ### channel id:{}\nmsg:\n{}", ctx.channel().id().asShortText(), msg);

        onChannelRead(ctx, msg);
        AsyncEventUtil.postEvent(new ChannelReadEvent(ctx, msg));
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        log.info("### userEventTriggered  ### channel id:{} event:{}", ctx.channel().id().asShortText(), evt);

        if (evt instanceof IdleStateEvent idleStateEvent) {
            AsyncEventUtil.postEvent(new ChannelIdleEvent(ctx, idleStateEvent));
        }
    }

    protected void onChannelRead(ChannelHandlerContext ctx, Msg msg) {
    }

}
